#ifndef _XP_MODBUS_H
#define _XP_MODBUS_H

#include "common_list.h"

#define XP_MAX_NUMBER_OF_MODBUS_DEVICE (20)
#define XP_MAX_LENGTH_OF_MODBUS_NAME (32)

enum xp_modbus_func
{
    mb_write_coil_reg = 0x05,
    mb_read_coil_reg = 0x01,
    mb_write_single_reg = 0x06,
    mb_read_single_reg = 0x03,
    mb_write_mult_reg = 0x10,
};

struct xp_modbus_bus;

// 定义modbus设备，对于modbus设备自身的一些属性，将其封装为单独的结构体并使用mb_attr指向它
typedef struct xp_modbus_device
{
    struct xp_slist_node dev_node;                    // 设备的链表节点，将设备挂接到modbus总线的链表上
    unsigned char name[XP_MAX_LENGTH_OF_MODBUS_NAME]; // 设备名
    unsigned char sid;                                // modbus从设备的ID
    unsigned char inited;                             // modbus设备初始化标记
    struct xp_modbus_bus *bus;                        // 设备所挂接的modbus总线

    void *device_attr; // modbus设备的私有属性
} xp_modbus_device_t;

struct xp_modbus_bus
{
    unsigned char name[XP_MAX_LENGTH_OF_MODBUS_NAME];      // 总线名字
    unsigned char sid_set[XP_MAX_NUMBER_OF_MODBUS_DEVICE]; // 设备ID集合
    unsigned char num_of_dev;                              // 设备数量
    unsigned char port;                                    // 总线端口或ID
    struct xp_slist_handler dev_list;                      // 设备链表句柄

    void *private_data; // modbus可能建立在串口或网络协议上，不同底层协议属性封装对应的结构体

    /* 总线初始化函数，对于串口则是对串口的初始化，总线属性初始化等 */
    int (*init)(struct xp_modbus_bus *bus);
    /* modbus总线读取设备数据，根据func按需读取 */
    int (*read)(xp_modbus_device_t *dev, unsigned short addr, unsigned short *data, int len, enum xp_modbus_func func);
    /* modbus总线写入设备数据，根据func按需写入 */
    int (*write)(xp_modbus_device_t *dev, unsigned short addr, unsigned short *data, int len, enum xp_modbus_func func);
    /* modbus总线读单个寄存器，由于读写单个寄存器的情况很常见，所以这里增加简化的读写单个寄存器的接口 */
    int (*sread)(xp_modbus_device_t *dev, unsigned short addr, unsigned short *data);
    /* modbus总线写单个寄存器 */
    int (*swrite)(xp_modbus_device_t *dev, unsigned short addr, unsigned short data);
};

/* 
 新增modbus设备后需要通过这个函数将设备挂接到总线上，
 后续设备驱动才能通过modbus设备中的总线读写方法与设备交互
 */
extern int xp_modbus_device_mount(struct xp_modbus_bus *bus, struct xp_modbus_device *dev);
extern int xp_modbus_device_unmount(struct xp_modbus_bus *bus, struct xp_modbus_device *dev);

#endif
